import Knex from "~/src/library/mysql";
import moment from "moment";
import _ from "lodash";
import Logger from "~/src/library/logger";
import redis from "~/src/library/redis";
import MCityDistribution from "~/src/model/parse/city_distribution";
import DATE_FORMAT from "~/src/constants/date_format";
import DatabaseUtil from "~/src/library/utils/modules/database";
const TABLE_COLUMN = [
  `id`,
  `code`,
  `time`,
  `msg`,
  `url_path`,
  `api_path`,
  `city_distribution_id`,
  `count_at_time`,
  `count_type`,
  `error_count`,
  `create_time`,
  `update_time`,
];

const BASE_TABLE_NAME = "t_r_api_summary";
const MAX_LIMIT = 100;

const BASE_REDIS_KEY = "api_summary";
const REDIS_KEY_ERROR_NAME_DISTRIBUTION_CACHE =
  BASE_REDIS_KEY + "_" + "api_distribution_cache";

/**
 * 获取表名
 * @param {number} projectId 项目id
 * @param {number} createTimeAt 创建时间, 时间戳
 * @return {String}
 */
function getTableName(projectId, createTimeAt) {
  const DATE_FORMAT = "YYYYMM";
  let YmDate = moment.unix(createTimeAt).format(DATE_FORMAT);
  return BASE_TABLE_NAME + "_" + projectId; //+ "_" + YmDate
}

async function insertApiSummaryRecord(
  projectId,
  countAt,
  countType,
  code,
  time,
  msg,
  urlPath,
  apiPath,
  cityDistribute
) {
  const tableName = getTableName(projectId, countAt);
  const countAtTime = moment
    .unix(countAt)
    .format(DATE_FORMAT.DATABASE_BY_UNIT[countType]);
  const createTime = moment().unix();
  // 先插城市分布数据获取id
  const cityDistributionId = await MCityDistribution.insertCityDistributionRecord(
    JSON.stringify(cityDistribute),
    projectId,
    countAt
  );
  const insertData = {
    code: code,
    time: time,
    msg: msg,
    url_path: urlPath,
    api_path: apiPath,
    city_distribution_id: cityDistributionId,
    count_at_time: countAtTime,
    count_type: countType,
    create_time: createTime,
    update_time: createTime,
  };
  const result = await Knex.insert(insertData, ["id"])
    .into(tableName)
    .catch(err => {
      Logger.error(err.message);
      return [0];
    });
  return _.get(result, [0], 0) > 0;
}
/**
 * 获取一段时间内的所有url列表, 方便进行汇总计算
 * @param {*} projectId
 * @param {*} indicatorList
 * @param {*} startAt
 * @param {*} endAt
 * @param {*} countType
 */
async function getDistinctApiListInRange(
  projectId,
  startAt,
  endAt,
  countType = DATE_FORMAT.UNIT.MINUTE
) {
  let startAtMoment = moment.unix(startAt).startOf(countType);
  let urlList = [];
  // const tableName = getTableName(projectId, startAt)
  // console.log(tableName)
  let tableNameList = DatabaseUtil.getTableNameListInRange(
    projectId,
    startAt,
    endAt,
    getTableName
  );
  let countAtTimeList = [];
  // 获取所有可能的countAtTime
  for (
    let countStartAtMoment = startAtMoment.clone();
    countStartAtMoment.unix() < endAt;
    countStartAtMoment = countStartAtMoment.clone().add(1, countType)
  ) {
    let formatCountAtTime = countStartAtMoment.format(
      DATE_FORMAT.DATABASE_BY_UNIT[countType]
    );
    countAtTimeList.push(formatCountAtTime);
  }
  // 循环查询数据库
  for (let tableName of tableNameList) {
    // const tableName = getTableName(projectId, countAt);
    let rawRecordList = await Knex.select([`api_path`])
      .from(tableName)
      .where("count_type", "=", countType)
      .whereIn("count_at_time", countAtTimeList)
      .catch(e => {
        Logger.warn("查询失败, 错误原因 =>", e);
        return [];
      });

    for (let rawRecord of rawRecordList) {
      if (_.has(rawRecord, ["api_path"])) {
        let raw = _.get(rawRecord, ["api_path"]);
        urlList.push(raw);
      }
    }
  }
  let distinctUrlList = _.union(urlList);
  return distinctUrlList;
}

/**
 * 计算api成功率，错误数据
 * @param {*} projectId
 * @param {*} indicatorList
 * @param {*} startAt
 * @param {*} endAt
 * @param {*} countType
 */
async function getApiTotalInRange(
  projectId,
  startAt,
  endAt,
  countType = DATE_FORMAT.UNIT.MINUTE
) {
  let startAtMoment = moment.unix(startAt).startOf(countType);
  const tableName = getTableName(projectId, startAtMoment);
  let countAtTimeList = [];
  // 获取所有可能的countAtTime
  for (
    let countStartAtMoment = startAtMoment.clone();
    countStartAtMoment.unix() < endAt;
    countStartAtMoment = countStartAtMoment.clone().add(1, countType)
  ) {
    let formatCountAtTime = countStartAtMoment.format(
      DATE_FORMAT.DATABASE_BY_UNIT[countType]
    );
    countAtTimeList.push(formatCountAtTime);
  }
  // 循环查询数据库
  let rawRecordList = await Knex.select([
    `api_path`,
    `time`,
    `code`,
    `id`,
    `url_path`,
    `msg`,
  ])
    .from(tableName)
    .where("count_type", "=", countType)
    .whereIn("count_at_time", countAtTimeList)
    .catch(e => {
      Logger.warn("查询失败, 错误原因 =>", e);
      return [];
    });
  let errorCount = 0;
  let MoOneSecondCount = 0;
  for (let rawRecord of rawRecordList) {
    let code = _.get(rawRecord, "code", 0);
    let time = _.get(rawRecord, "time", 0);
    if (code === "" || code == "FAILED") {
      errorCount++;
    }
    if (time === "" || time > 1000) {
      MoOneSecondCount++;
    }
  }
  let successRate =
    rawRecordList.length > 0
      ? `${(
          ((rawRecordList.length - errorCount) / rawRecordList.length) *
          100
        ).toFixed(0)}%`
      : "100%";
  let raw = {
    errorCount: errorCount,
    successRate: successRate,
    MoOneSecondCount: MoOneSecondCount,
  };
  return raw;
}

async function get(
  projectId,
  countAt,
  countType,
  errorType,
  errorName,
  urlPath
) {
  const tableName = getTableName(projectId, countAt);
  const countAtTime = moment
    .unix(countAt)
    .format(DATE_FORMAT.DATABASE_BY_UNIT[countType]);

  const wherePrams = {
    count_at_time: countAtTime,
    count_type: countType,
    error_name: errorName,
    url_path: urlPath,
  };
  const result = await Knex.select(TABLE_COLUMN)
    .from(tableName)
    .where(wherePrams)
    .catch(err => {
      Logger.error(err.message);
      return [];
    });
  return _.get(result, [0], {});
}

/**
 * 生成同一月内的指标数据
 * @param {*} projectId
 * @param {*} api
 * @param {*} startAt
 * @param {*} endAt
 * @param {*} countType
 */
async function getApiStatisticsData(projectId, api, startAt, endAt, countType) {
  let startAtMoment = moment.unix(startAt).startOf(countType);
  let urlList = [];
  let tableName = getTableName(projectId, startAt);
  let countAtTimeList = [];
  // 获取所有可能的countAtTime
  for (
    let countStartAtMoment = startAtMoment.clone();
    countStartAtMoment.unix() < endAt;
    countStartAtMoment = countStartAtMoment.clone().add(1, countType)
  ) {
    let formatCountAtTime = countStartAtMoment.format(
      DATE_FORMAT.DATABASE_BY_UNIT[countType]
    );
    countAtTimeList.push(formatCountAtTime);
  }
  // 查询数据库
  let rawRecordList = await Knex.select(["time", "url_path", "count_at_time"])
    .from(tableName)
    .where({
      count_type: countType,
    })
    .where("api_path", api)
    .whereIn("count_at_time", countAtTimeList)
    .catch(e => {
      Logger.warn("查询失败, 错误原因 =>", e);
      return [];
    });
  let res = {
    urlList: [],
    sumTime: 0,
    pageNum: 0,
  };
  let totalTime = 0;
  for (let rawRecord of rawRecordList) {
    let time = _.get(rawRecord, ["time"], 0);
    let url = _.get(rawRecord, ["url_path"], "");
    totalTime = totalTime + parseInt(time);
    urlList.push(url);
  }
  res.sumTime = (totalTime / rawRecordList.length / 1000).toFixed(2);
  for (let u of _.union(urlList)) {
    let item = {
      number: 0,
      url: u,
    };
    for (let rawRecord of rawRecordList) {
      let url = _.get(rawRecord, ["url_path"], "");
      if (url == u) {
        item.number++;
      }
    }
    res.urlList.push(item);
  }
  res.pageNum = _.union(urlList).length;
  // for (let row of rawRecordList) {
  //   let countAtTime = _.get(row, ["count_at_time"], 0);
  //   let unixKey = moment(
  //     countAtTime,
  //     DATE_FORMAT.DATABASE_BY_UNIT[countType]
  //   ).unix();
  //   console.log(unixKey)
  //   let result = _.get(lineChartDataMap, [unixKey], 0);

  // }
  return res;
}
async function getList(
  projectId,
  startAt,
  endAt,
  countType,
  errorNameList = [],
  url = ""
) {
  const tableName = getTableName(projectId, startAt);
  let timeList = DatabaseUtil.getDatabaseTimeList(startAt, endAt, countType);

  let extendCondition = {};
  if (url.length > 0) {
    extendCondition["url_path"] = url;
  }

  let rawRecordList = await Knex.select(TABLE_COLUMN)
    .from(tableName)
    .where("count_type", countType)
    .whereIn("count_at_time", timeList)
    .whereIn("error_name", errorNameList)
    .andWhere(extendCondition)
    .orderBy("error_count", "desc")
    .catch(err => {
      Logger.error(err.message);
      return [];
    });
  if (rawRecordList.length === 0) return [];
  let cityDistributionIdList = [];
  let createAt = 0;
  for (let rawRecord of rawRecordList) {
    let cityDistributionId = _.get(rawRecord, ["city_distribution_id"], 0);
    createAt = _.get(rawRecord, ["create_time"], 0);
    cityDistributionIdList.push(cityDistributionId);
  }
  let rawCityDistributionReocrdList = await MCityDistribution.getByIdListInOneMonth(
    projectId,
    cityDistributionIdList,
    createAt
  );

  let cityDistributionMap = {};
  for (let rawRecord of rawCityDistributionReocrdList) {
    let cityDistributionJson = _.get(rawRecord, ["city_distribute_json"], "{}");
    let cityDistributionId = _.get(rawRecord, ["id"], 0);
    let cityDistribution = {};
    try {
      cityDistribution = JSON.parse(cityDistributionJson);
    } catch (e) {
      cityDistribution = {};
    }
    cityDistributionMap[cityDistributionId] = cityDistribution;
  }
  let recordList = [];
  for (let rawRecord of rawRecordList) {
    let cityDistributionId = _.get(rawRecord, ["city_distribution_id"], 0);
    let cityDistribution = _.get(cityDistributionMap, [cityDistributionId], {});
    rawRecord["city_distribution"] = cityDistribution;
    recordList.push(rawRecord);
  }
  return recordList;
}

export default {
  insertApiSummaryRecord,
  getTableName,
  getDistinctApiListInRange,
  get,
  getApiTotalInRange,
  getApiStatisticsData,
  getList,
};
